package com.itheima.stock.service.impl;

import com.google.common.base.Strings;
import com.itheima.stock.common.domain.OwnRoleAndAllRoleIdsDomain;
import com.itheima.stock.common.domain.PermissionDomain;
import com.itheima.stock.mapper.SysUserMapper;
import com.itheima.stock.pojo.SysPermission;
import com.itheima.stock.pojo.SysUser;
import com.itheima.stock.service.UserService;
import com.itheima.stock.utils.IdWorker;
import com.itheima.stock.vo.req.ConditionQueryUserReq;
import com.itheima.stock.vo.req.LoginReqVo;
import com.itheima.stock.vo.resp.*;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.security.Permission;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 分布式环境保证生成id唯一
     */
    @Autowired
    private IdWorker idWorker;

    /*
        用户登录功能实现
        功能描述：当前用户登录后，仅仅加载了用户表相关信息，接下来完成的功能是完善用户权限相关的信息；
        服务路径：/api/login
        请求方式：POST
     */
    @Override
    public R<newLoginRespVo> login(LoginReqVo vo) {
        if (vo == null || Strings.isNullOrEmpty(vo.getUsername()) || Strings.isNullOrEmpty(vo.getPassword())) {
            return R.error(ResponseCode.DATA_ERROR.getMessage());
        }
        //验证码校验
        // 先判断是否存在验证码或者idworks生成的唯一性标识
        if (Strings.isNullOrEmpty(vo.getCode()) || Strings.isNullOrEmpty(vo.getRkey())) {
            return R.error(ResponseCode.DATA_ERROR.getMessage());
        }
        // 获取redis中rkey对应的code验证码 根据sessionId 获取 生成的随机的四位验证码
        String rCode = (String) redisTemplate.opsForValue().get(vo.getRkey());
        // 获取前端传入的密码
        String code = vo.getCode();
        //校验
        if (Strings.isNullOrEmpty(rCode) || !rCode.equals(code)) {
            return R.error(ResponseCode.DATA_ERROR.getMessage());
        }
        //redis清除key
        redisTemplate.delete(vo.getRkey());
        // 根据用户名查询用户及其权限信息
        SysUser user = sysUserMapper.getUserPermissionInfo(vo.getUsername());
        //System.out.println(userPermInfo);
        // 将user中查询的数据封装到newLoginRespVo中
        newLoginRespVo result = new newLoginRespVo();
        BeanUtils.copyProperties(user, result);
        // 将数据中的按钮权限(perms) 封装到result中
        List<String> permissions = new ArrayList<>();
        List<SysPermission> sysPermissions = user.getPermissions();
        for (SysPermission p : sysPermissions) {
            if (!Strings.isNullOrEmpty(p.getPerms())) {
                permissions.add(p.getPerms());
            }
        }
        result.setPermissions(permissions);
        // 处理权限树的方法 从上往下
        // 获取根节点(父级权限)
        List<PermissionDomain> menus = user.getPermissions().stream()
                .filter(s -> "0".equals(s.getPid())).map(item -> {
                    PermissionDomain pmd = new PermissionDomain();
                    // 转换数据类型 syspermission -> permissiondomain
                    pmd.setId(item.getId());
                    pmd.setName(item.getName());
                    pmd.setIcon(item.getIcon());
                    pmd.setTitle(item.getTitle());
                    pmd.setPath(item.getUrl());
                    // 获取SysPermission类型的子权限树 传入的参数是 根节点的 id 和 采集到的syspermission类型数据
                    List<SysPermission> childMenus = getChildMenus(item.getId(), user.getPermissions());
                    item.setChildren(childMenus);
                    // 拷贝子权限树 类型转换 将syspermission类型的权限树 转换为 前端需要的permissionDomain
                    pmd.setChildren(new ArrayList<>());
                    pmd.setChildren(copyChildren(item.getChildren(), pmd.getChildren()));
                    return pmd;
                }).collect(Collectors.toList());
        result.setMenus(menus);
        return R.ok(result);
/*
            //根据用户名查询用户信息
            SysUser user = sysUserMapper.findByUserName(vo.getUsername());
            //判断查询是否存在
            if (user == null) {
                return R.error(ResponseCode.DATA_ERROR.getMessage());
            }
            //判断密码是否匹配
            if (!passwordEncoder.matches(vo.getPassword(), user.getPassword())) {
                return R.error(ResponseCode.SYSTEM_PASSWORD_ERROR.getMessage());
            }
            //组装登录成功数据
            LoginRespVo respVo = new LoginRespVo();
            //属性名称与类型必须相同，否则copy不到
            BeanUtils.copyProperties(user, respVo);
            return R.ok(respVo);

*/
    }

    /**
     * @param id   父权限id
     * @param list 权限数据
     * @return 子权限集合
     */
    private List<SysPermission> getChildMenus(String id, List<SysPermission> list) {
        // 创建容器 存放子权限
        List<SysPermission> children = new ArrayList<>();
        // 根据传过来的父权限id查询所有子权限
        list.forEach(s -> {
            if (id.equals(s.getPid())) {
                children.add(s);
            }
        });
        children.forEach(s -> s.setChildren(getChildMenus(s.getId(), list)));
        return children;
    }

    private List<PermissionDomain> copyChildren(List<SysPermission> sysList, List<PermissionDomain> perList) {
        if (sysList != null && sysList.size() != 0) {
            for (SysPermission sysp : sysList) {
                PermissionDomain p = new PermissionDomain();
                p.setChildren(new ArrayList<PermissionDomain>());
                // 类型转换
                p.setId(sysp.getId());
                p.setTitle(sysp.getTitle());
                p.setIcon(sysp.getIcon());
                p.setPath(sysp.getUrl());
                p.setName(sysp.getName());
                perList.add(p);
                // 判断子权限是否还是子权限
                if(sysp.getChildren().size() !=0){
                    copyChildren(sysp.getChildren(),p.getChildren());
                }
            }
        }
        return perList;
    }

    /**
     * 生成验证码
     * 使用redis 模仿session来生成随机验证码并且返回给前端
     * map结构：
     * code： xxx,
     * rkey: xxx
     *
     * @return
     */
    @Override
    public R<Map> generateCaptcha() {
        //1.生成4位数字验证码
        String checkCode = RandomStringUtils.randomNumeric(4);
        //2.获取全局唯一id  使用idworker工具类自动生成
        long l = idWorker.nextId();// 因为前端接收和返回都会是string类型这边先转换为string类型
        // 模拟sessionid来存储到redis中
        String sessionId = String.valueOf(l);
        //验证码存入redis中，并设置有效期1分钟
        redisTemplate.opsForValue().set(sessionId, checkCode, 60, TimeUnit.SECONDS);
        //3.组装数据
        HashMap<String, String> map = new HashMap<>();
        map.put("rkey", sessionId);
        map.put("code", checkCode);
        return R.ok(map);
    }

    /*
        功能描述：多条件综合查询用户分页信息，条件包含：分页信息 用户创建日期范围
        服务路径：/api/users
        服务方法：Post
     */
    @Override
    public R<ConditionQueryUserResp> conditionsQueryUser(ConditionQueryUserReq req) {
        // 1 创建一个容器存放数据
        ConditionQueryUserResp resp = new ConditionQueryUserResp();
        // 2 调用mapper层对象
        List<SysUser> users = sysUserMapper.conditionsQueryUser(req);
        // 3 封装数据
        resp.setTotalRows(users.size());
        int pageSize = Integer.parseInt(req.getPageSize());
        Integer pageCount = (users.size() + pageSize - 1) / pageSize;
        resp.setTotalPages(pageCount);
        resp.setPageNum(Integer.parseInt(req.getPageNum()));
        resp.setPageSize(pageSize);
        resp.setSize(users.size());
        resp.setRows(users);
        return R.ok(resp);
    }

    /*
        功能描述：添加用户信息
        服务路径：/api/users
        测试路径: /api/addUsers
        服务方法：Post
     */
    @Override
    public R addUsers(SysUser adduser) {
        // 调用mapper层方法
        adduser.setId(new IdWorker().nextId() + "");
        sysUserMapper.insertUser(adduser);
        return R.ok("操作成功");
    }
}
